<?php

class ApiController extends Controller {

    /**
     * @var int
     */
    protected $_userId;

    public function init()
    {
        $this->_userId = Yii::app()->user->model->id;
        parent::init();
    }

    /**
     * @throws Exception
     */
    public function actionTodoSync()
    {
        $res = array(
            'data'   => array(),
            'errors' => array()
        );

        try {
            if (Yii::app()->user->isGuest) {
                throw new Exception('Not logged');
            }

            $this->_processCategories();
            $this->_processItems();

            $items = $this->_getItems();
            $categories = $this->_getCategories();

            $res['data'] = array(
                'items'      => $items,
                'categories' => $categories
            );
        } catch (Exception $e) {
            $res['errors'][] = $e->getMessage();
        }

        if (sizeof($res['errors'])) {
            header('HTTP/1.1 400 Bad Request');
        }

        echo CJSON::encode($res);
    }

    protected function _processItems()
    {
        $req = Yii::app()->request->getParam('items');
        if (!$req || !is_array($req) && $req != 'no items') {
            throw new Exception('Bad request. No items sent.');
        }

        if (is_array($req)) {
            $names = Todo::model()->findAll(array(
                                                 'select'    => 't.name, t.user_id',
                                                 'distinct'  => true,
                                                 'condition' => 't.user_id = :userId AND (delete_date IS NULL AND complete_date IS NULL)',
                                                 'params'    => array(
                                                     ':userId' => $this->_userId
                                                 )
                                            ));


            foreach ($req as $item) {
                $this->_checkDataFields($item, 'id,name,completed,deleted');

                /**
                 * @var $model Todo
                 */

                if ($item['id'] == 'new') {
                    $this->_createItem($names, $item);
                } else {
                    $this->_editItem($names, $item);
                }
            }
        }
    }

    protected function _createItem($names, $item)
    {
        $name = trim(strip_tags($item['name']));

        if (empty($name)) {
            return;
        }

        if (strpos($name, '@') !== 0 and preg_match('/(.+)@.+/', $name, $t)) {
            $todo = Todo::model()->find('name = :name AND (delete_date IS NULL OR complete_date IS NULL)', array(
                                                                                                                ':name' => trim(strip_tags($t[1]))
                                                                                                           ));
            if ($todo) return;
        }

        $isExists = false;

        foreach ($names as $nameItem) {
            if ($name == $nameItem->name) {
                $isExists = true;
                break;
            }
        }

        if ($isExists) return;

        $model = new Todo();
        $model->user_id = $this->_userId;
        $model->category_id = new CDbExpression('NULL');

        $model->name = $name;

        if (preg_match('/#([\d]{2})\/([\d]{2})/', $model->name, $t)) {
            if (intval($t[1]) >= 1 && intval($t[1]) <= 31 && intval($t[2]) >= 1 && intval($t[2]) <= 12) {
                $model->deadline = date('Y-m-d H:i:s', strtotime($t[2] . '/' . $t[1]));
            }
        }

        if (strpos($name, '@') !== 0 and preg_match('/@(.+)/', $name, $t)) {
            $model->name = preg_replace('/@.+/', '', $name);
            $category_name = $t[1];
            $category = Category::model()->find('name = :name AND user_id = :user_id', array(
                                                                                            ':name'    => $category_name,
                                                                                            ':user_id' => $this->_userId
                                                                                       ));

            if (!$category) {
                $category = new Category();
                $category->user_id = $this->_userId;
                $category->name = $category_name;

                if ($category->validate()) {
                    $category->save();
                    $model->category_id = $category->id;
                }
            } else {
                $model->category_id = $category->id;
            }
        }

        if (isset($item['category_id']) && $item['category_id'] > 0) {
            $model->category_id = $item['category_id'];
        }

        $model->create_date = new CDbExpression('NOW()');
        $model->sync_date = new CDbExpression('NOW()');
        $model->position = isset($item['position']) ? $item['position'] : 0;

        if ($item['completed'] == 'true') {
            $model->complete_date = new CDbExpression('NOW()');
        }
        if ($item['deleted'] == 'true') {
            $model->delete_date = new CDbExpression('NOW()');
        }

        if ($model->validate()) {
            $model->save();
        }
    }

    protected function _editItem($names, $item)
    {
        $model = Todo::model()->findByPk($item['id']);

        $name = $item['name'];
        $todo = Todo::model()->find('name = :name', array(':name' => trim(strip_tags($name))));

        if ($todo and $model->id != $todo->id) return;

        if (strpos($name, '@') !== 0 and preg_match('/(.+)@.+/', $name, $t)) {
            $todo = Todo::model()->find('name = :name', array(':name' => trim(strip_tags($t[1]))));
            if ($todo and $model->id != $todo->id) return;
        }

        if ($model) {
            $isModified = false;

            if ($model->user_id != $this->_userId) {
                return;
            }

            if ($item['completed'] == 'true' && !$model->complete_date) {
                $model->complete_date = new CDbExpression('NOW()');
                $isModified = true;
            }

            if ($item['deleted'] == 'true' && !$model->delete_date) {
                $model->delete_date = new CDbExpression('NOW()');
                $isModified = true;
            }

            $model->position = abs(intval(isset($item['position']) ? $item['position'] : $model->position));

            if ($item['name'] != $model->name) {
                $model->name = trim(strip_tags($item['name']));

                $isModified = true;

                if (preg_match('/#([\d]{2})\/([\d]{2})/', $model->name, $t)) {
                    if (intval($t[1]) >= 1 && intval($t[1]) <= 31 && intval($t[2]) >= 1 && intval($t[2]) <= 12) {
                        $model->deadline = date('Y-m-d H:i:s', strtotime($t[2] . '/' . $t[1]));
                    }
                }

                if (strpos($model->name, '@') !== 0 and preg_match('/@(.+)/', $model->name, $t)) {
                    $model->name = preg_replace('/@.+/', '', $model->name);
                    $category_name = $t[1];
                    $category = Category::model()->find('name = :name AND user_id = :user_id', array(
                                                                                                    ':name'    => $category_name,
                                                                                                    ':user_id' => $this->_userId
                                                                                               ));

                    if (!$category) {
                        $category = new Category();
                        $category->user = Yii::app()->user->model;
                        $category->name = $category_name;

                        if ($category->validate()) {
                            $category->save();
                            $model->category_id = $category->id;
                        }
                    } else {
                        $model->category_id = $category->id;
                    }
                }
            }

            if (isset($item['category_id'])) {
                $category = Category::model()->findByPk(intval($item['category_id']));

                if ($category) {
                    $model->category_id = $category->id;
                    $isModified = true;
                } elseif ($model->category_id != null) {
                    $model->category_id = null;
                }
            }

            if ($isModified) {
                $model->modify_date = new CDbExpression('NOW()');
            }

            $model->sync_date = new CDbExpression('NOW()');

            if ($model->validate()) {
                $model->save();
            }
        }

    }

    protected function _processCategories()
    {
        $req = Yii::app()->request->getParam('categories');
        if (!$req || !is_array($req) && $req != 'no categories') {
            throw new Exception('Bad request. No categories sent.');
        }

        if (is_array($req)) {
            foreach ($req as $item) {

                $this->_checkDataFields($item, 'id,name,deleted');

                /**
                 * @var $model Todo
                 */

                if ($item['id'] == 'new') {
                    $this->_createCategory($item);
                } else {
                    $this->_editCategory($item);
                }
            }
        }
    }

    protected function _createCategory($item)
    {
        $name = trim(strip_tags($item['name']));
        $name = str_replace('@', '', $name);

        if (empty($name)) {
            return;
        }

        $category = Category::model()->find('name = :name AND user_id = :user_id', array(
                                                                                        ':name'    => $name,
                                                                                        ':user_id' => $this->_userId
                                                                                   ));

        if (!$category) {
            $category = new Category();
            $category->user_id = $this->_userId;
            $category->name = $name;
            $category->position = isset($item['position']) ? $item['position'] : 0;

            if ($category->validate()) $category->save();
        }
    }

    public function _editCategory($item)
    {
        $name = trim(strip_tags($item['name']));
        $name = str_replace('@', '', $name);
        if (empty($name)) {
            return;
        }

        $category = Category::model()->findByPk($item['id']);

        if ($category and $item['deleted'] == 'true') {
            $cat_id = $category->id;

            //$category->delete();
            //Todo::model()->updateAll(array('category' => null), "category_id = '{$cat_id}'");

            return;
        }

        if ($category) {
            $category->name = $name;
            $category->position = isset($item['position']) ? $item['position'] : $category->position;

            if ($category->validate()) $category->save();
        }
    }

    protected function _getItems()
    {
        $result = array();
        //don't selecting completed items
        $dbRes = Todo::model()->findAll(array(
                                             'order'     => 'deadline IS NULL ASC, deadline > NOW() ASC, position ASC',
                                             'condition' => 'user_id=:userId AND delete_date IS NULL AND complete_date IS NULL',
                                             'params'    => array(
                                                 ':userId' => $this->_userId,
                                             )
                                        ));


        foreach ($dbRes as $item) {
            /**
             * @var $item Todo
             */
            $result[] = array(
                'id'          => $item->id,
                'name'        => trim(strip_tags($item->name)),
                'completed'   => !is_null($item->complete_date),
                'deleted'     => !is_null($item->delete_date),
                'deadline'    => (is_null($item->deadline) ? null : date('d/m', strtotime($item->deadline))),
                'expired'     => $item->isExpired(),
                'category_id' => $item->category_id,
                'position'    => $item->position
            );
        }

        return $result;
    }

    protected function _getCategories()
    {
        //c3 start
        $dbRes = Category::model()->findAll(array(
                                                 'order'     => 't.position ASC',
                                                 'condition' => 'user_id = :user_id',
                                                 'params'    => array(':user_id' => $this->_userId)
                                            ));

        $result = array();

        foreach ($dbRes as $item) {
            /**
             * @var $item Todo
             */
            $result[] = array(
                'id'       => $item->id,
                'name'     => trim(strip_tags($item->name)),
                'deleted'  => false,
                'position' => $item->position
            );
        }

        return $result;
    }

    protected function _checkDataFields($data, $field_list)
    {
        $field_list = explode(',', $field_list);

        foreach ($field_list as $field) {
            if (!isset($data[$field])) {
                throw new Exception('Bad request. One property not found.' . $field);
            }
        }
    }

}